package com.back.uart;

import cn.hutool.core.util.StrUtil;
import com.back.Dao.DeviceData;
import com.back.Mapper.DeviceDataMapper;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
public class SerialConfig {

    public static DeviceData deviceData = new DeviceData();
    public static String data;

    @Autowired
    private static SerialPort serialPort;

    @Autowired
    private  DeviceDataMapper deviceDataMapper;

    public  SerialPort Open()
    {
        SerialPort[] serialPorts = SerialPort.getCommPorts();//查找所有串口
        if(serialPorts.length > 0)
        {
            serialPort = serialPorts[0];//获取到第一个串口
            serialPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);//一次性设置所有的串口参数，第一个参数为波特率，默认9600；第二个参数为每一位的大小，默认8，可以输入5到8之间的值；第三个参数为停止位大小，只接受内置常量，可以选择(ONE_STOP_BIT, ONE_POINT_FIVE_STOP_BITS, TWO_STOP_BITS)；第四位为校验位，同样只接受内置常量，可以选择 NO_PARITY, EVEN_PARITY, ODD_PARITY, MARK_PARITY,SPACE_PARITY。
            if(!serialPort.isOpen()){
                boolean isCommOpeded = serialPort.openPort();//判断串口是否打开，如果没打开，就打开串口。打开串口的函数会返回一个boolean值，用于表明串口是否成功打开了
            }
        }
        return serialPort;
    }

    public void ReadData()
    {
        SerialPort serialPort = Open();
        if(serialPort.isOpen()){

            String readData = "";
            while(serialPort.bytesAvailable()>0){//循环读取所有的返回数据。如果可读取数据长度为0或-1，则停止读取
                byte[] newData = new byte[serialPort.bytesAvailable()];//创建一个字节数组，长度为可读取的字节长度
                int numRead = serialPort.readBytes(newData, newData.length);//将串口中可读取的数据读入字节数组，返回值为本次读取到的字节长度
                String newDataString = new String(newData);//将新数据转为字符串
                readData = readData + newDataString;//组合字符串
                try {
                    Thread.sleep(20);//休眠0.02秒，等待下位机传送数据到串口。如果不休眠，直接再次使用port.bytesAvailable()函数会因为下位机还没有返回数据而返回-1，并跳出循环导致数据没读完。休眠时间可以自行调试，时间越长，单次读取到的数据越多。
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // SaveData(readData);
            System.out.println("readString:"+readData);
        }


    }

    @PostConstruct
    public void ReadDataLister()
    {
        SerialPort serialPort = Open();
        if(serialPort != null && serialPort.isOpen()){
            serialPort.addDataListener(new SerialPortDataListener() {//添加监听器。由于该监听器有两个函数，无法使用Lambda表达式

                @Override
                public int getListeningEvents() {
                    // TODO Auto-generated method stub
                    return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;//返回要监听的事件类型，以供回调函数使用。可发回的事件包括：SerialPort.LISTENING_EVENT_DATA_AVAILABLE，SerialPort.LISTENING_EVENT_DATA_WRITTEN,SerialPort.LISTENING_EVENT_DATA_RECEIVED。分别对应有数据在串口（不论是读的还是写的），有数据写入串口，从串口读取数据。如果AVAILABLE和RECEIVED同时被监听，优先触发RECEIVED
                }


                @Override
                public void serialEvent(SerialPortEvent event) {//事件处理函数
                    data = "";
                    if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE){
                        return;//判断事件的类型
                    }
                    if(serialPort.bytesAvailable()!=0) {

                        byte[] newData = new byte[serialPort.bytesAvailable()];
                        int numRead = serialPort.readBytes(newData, newData.length);
                        data = new String(newData);
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("readString:"+data);
                        //SaveData(data);
                    }//同样使用循环读取法读取所有数据
                    //由于这里是监听函数，所以也可以不使用循环读取法，在监听器外创建一个全局变量，然后将每次读取到的数据添加到全局变量里

                }

            });
        }


    }


    @Scheduled(fixedRate = 5000)
    public void SaveData()
    {

        if(data != null)
        {
            if(!StrUtil.isEmpty(data)) {
            deviceData.setDeviceId(Integer.parseInt(data.substring(0,1)));
            deviceData.setTemp(data.substring(2, 6));
            deviceData.setHum(data.substring(8, 12));
            deviceData.setLight(data.substring(14));
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            deviceData.setUploadDate(now.format(formatter));
            deviceDataMapper.addDeviceData(deviceData);
        }

        if(!StrUtil.isEmpty(data)) {
            deviceData.setDeviceId(Integer.parseInt(data.substring(0,1)));
            deviceData.setTemp(data.substring(2, 6));
            deviceData.setHum(data.substring(8, 12));
            deviceData.setLight(data.substring(14));
            //deviceData.setLight(data.substring());
                LocalDateTime now = LocalDateTime.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                deviceData.setUploadDate(now.format(formatter));
                System.out.println(deviceData.getDeviceId() + " " + deviceData.getTemp() + " " + deviceData.getHum() + " " + deviceData.getUploadDate());
                deviceDataMapper.addDeviceData(deviceData);
        }

        }
    }
}
